// 泛型参数可以有任意多个
/* function test<T, K>(a: T, b: K) {}
test<number, string>(8, 'abc') */

// 错误写法1
/* function getProp(obj, key) {
  return obj[key]
}

const o = {
  name: 'zs',
  age: 18,
}

// 参数1：对象
// 参数2：属性
// 目标：期望获取属性值
getProp(o, 'name') */

// 错误写法 1
/* function getProp(obj: { name: string; age: number }, key: string) {
  // key 是一个 string 可能在 { name: string; age: number } 找不到
  // 例如 key 是 'a'，是不是就是找不到呀
  return obj[key]
}

const o = {
  name: 'zs',
  age: 18,
}

// 参数1：对象
// 参数2：属性
// 目标：期望获取属性值
getProp(o, 'name') */

/* function getProp(obj: { name: string; age: number; sex: string }, key: 'name' | 'age' | 'sex') {
  // 这样写法，虽然没有报错，但是太固定了，
  // 传参的时候没有办法支持多种情况，一旦传递过来的数据改了，这个函数定义类型的地方都要改
  return obj[key]
}

const o = {
  name: 'zs',
  age: 18,
  sex: 'man',
}

// 参数1：对象
// 参数2：属性
// 目标：期望获取属性值
getProp(o, 'sex') */

// 多个泛型参数之间可以相互约束，其实 key 是应该受到对象的约束，说白了，key 只能是对象中的 key 中的某一个
// 一旦对象中的 key 变了（增加了或减少了），key 应该自动跟着变化

// keyof T => 'name' | 'age'
// K extends keyof T => K 要满足 'name' | 'age'，K 只能是 'name' 或 'age'
function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key]
}

const o = {
  name: 'zs',
  age: 18,
  address: '河南',
  sex: '男',
  arr: ['a'],
}

// 参数1：对象
// 参数2：属性
// 目标：期望获取属性值
getProp(o, 'address')
